import { BodyItemConstant } from '../constants/InputItemConstants';
import { CirculatoryDiseasesAdvicesConstants } from '../constants/CirculatoryDiseasesAdvicesConstants';
import CommonUtils from './CommonUtils';
import AdvicesLogic from './CirculatoryDiseasesAdvicesLogic';
import AdvicesUtils from './CirculatoryDiseasesAdvicesUtils';

const {
  GENDER,
  SMOKING_HABIT,
  DIABETES_CURE_FLG,
  BLOOD_SUGAR_LEVEL_FASTING,
  BLOOD_SUGAR_LEVEL_ANYTIME,
} = BodyItemConstant;

const {CALCULATE_RISK_LOW_FLG} = CirculatoryDiseasesAdvicesConstants;

/**
 * 脳卒中ロジック
 */
class CerebralStrokeLogic {

  /**
   * リスク計算
   * @param {number} gender 性別
   * @param {number} age 年齢
   * @param {number} smokingHabit 喫煙習慣
   * @param {number} bodyHeight 身長（cm）
   * @param {number} bodyWeight 体重（kg）
   * @param {number} bmi BMI
   * @param {number} diabetesCureFlg 糖尿病の治療
   * @param {number} bloodSugarLevelFasting 血糖値（空腹時）
   * @param {number} bloodSugarLevelAnytime 血糖値（随時）
   * @param {number} antihypertensiveFlg 降圧剤
   * @param {number} maxBloodPressure 最高（収縮期）血圧
   * @param {number} minBloodPressure 最低（拡張期）血圧
   * @return {Object.<Object>} 脳卒中危険度（自分、最大、最小）
   */

  static calcRisk({ gender, age, smokingHabit, bodyHeight, bodyWeight, diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime, antihypertensiveFlg, maxBloodPressure, minBloodPressure }) {
    // 69歳を超えた場合、69歳とみなす
    age = CommonUtils.convertAge(age); 
    // BMIを計算する
    const bmi = CommonUtils.calcBMI(bodyHeight, bodyWeight);  
    const genderVal = this._getGenderValue(gender);
    const ageVal = this._getAgeValue(age);
    const bmiVal = this._getBmiValue(bmi);
    const diabetesVal = this._getDiabetesValue(diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime);
    const bloodpressureVal = this._getBloodpressureValue(antihypertensiveFlg, maxBloodPressure, minBloodPressure);

    // probability:あなたのリスク、MINリスク、MAXリスク
    const results = {
      probability: {
        you: this._getProbability(genderVal, ageVal, this._getSmokingValue(smokingHabit, gender), bmiVal, diabetesVal, bloodpressureVal),
        min: this._getProbability(genderVal, ageVal, 0, 0, 0, 0),
        max: this._getProbability(genderVal, ageVal, this._getSmokingValue(SMOKING_HABIT.IS_SMOKING.value, gender), 3, 7, 15),
      },
    };
    return results;
  }

  /**
   * 性別算出値を生成します。
   * @param {number} gender 性別
   * @return {number} 性別算出値
   */
  static _getGenderValue(gender) {
    return gender === GENDER.MALE.value ? 6 : 0;
  }

  /**
   * 年齢算出値を生成します。
   * @param {number} age 年齢
   * @return {number} 年齢算出値
   */
  static _getAgeValue(age) {

    let ageVal;

    if (age < 45) {
      ageVal = 0;
    } else if (age >= 45 && age < 50) {
      ageVal = 5;
    } else if (age >= 50 && age < 55) {
      ageVal = 6;
    } else if (age >= 55 && age < 60) {
      ageVal = 12;
    } else if (age >= 60 && age < 65) {
      ageVal = 16;
    } else {
      ageVal = 19;
    }

    return ageVal;
  }

  /**
   * 喫煙算出値を生成します。
   * @param {number} smokingHabit 喫煙習慣
   * @param {number} gender 性別 
   * @return {number} 喫煙算出値
   */
  static _getSmokingValue(smokingHabit, gender) {
    
    let smokingHabitVal;
    
    if (smokingHabit === SMOKING_HABIT.IS_SMOKING.value) {
      if (gender === GENDER.MALE.value) {
        smokingHabitVal = 4;
      } else {
        smokingHabitVal = 8;
      }
    } else {
      smokingHabitVal = 0;
    }
    return smokingHabitVal;
  }

  /**
   * bmi算出値を生成します。
   * @param {number} bmi
   * @return {number} bmi算出値
   */
  static _getBmiValue(bmi) {

    let bmiVal;
    
    if (bmi < 25) {
      bmiVal = 0;
    } else if (bmi >= 25 && bmi < 30) {
      bmiVal = 2;
    } else {
      bmiVal = 3;
    }
    return bmiVal;
  }

  /**
   * 糖尿病算出値を生成します。
   * @param {number} diabetesCureFlg 糖尿病の治療
   * @param {number} bloodSugarLevelFasting 血糖値（空腹時）
   * @param {number} bloodSugarLevelAnytime 血糖値（随時）
   * @return {number} 糖尿病算出値
   */
  static _getDiabetesValue(diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime) {

    let diabetesVal;

    if (diabetesCureFlg === DIABETES_CURE_FLG.YES.value) {
      diabetesVal = 7;
    } else {
      if (bloodSugarLevelFasting >= BLOOD_SUGAR_LEVEL_FASTING.HIGH.value || bloodSugarLevelAnytime >= BLOOD_SUGAR_LEVEL_ANYTIME.HIGH.value) {
        diabetesVal = 7;
      } else {
        diabetesVal = 0;
      }
    }

    return diabetesVal;
  }

  /**
   * 血圧算出値を生成します。
   * @param {number} antihypertensiveFlg 降圧剤
   * @param {number} maxBloodPressure 最高（収縮期）血圧
   * @param {number} minBloodPressure 最低（拡張期）血圧
   * @return {number} 血圧算出値
   */
  static _getBloodpressureValue(antihypertensiveFlg, maxBloodPressure, minBloodPressure) {

    let bloodpressureVal;
    
    if (maxBloodPressure >= 180 || minBloodPressure >= 110) {
      bloodpressureVal = antihypertensiveFlg === 0 ? 13 : 15;
    } else if ((maxBloodPressure >= 160 && maxBloodPressure < 180) || (minBloodPressure >= 100 && minBloodPressure < 110)) {
      bloodpressureVal = 11;
    } else if ((maxBloodPressure >= 140 && maxBloodPressure < 160) || (minBloodPressure >= 90 && minBloodPressure < 100)) {
      bloodpressureVal = antihypertensiveFlg === 0 ? 8 : 11;
    } else if ((maxBloodPressure >= 130 && maxBloodPressure < 140) || (minBloodPressure >= 85 && minBloodPressure < 90)) {
      bloodpressureVal = antihypertensiveFlg === 0 ? 6 : 10;
    } else if ((maxBloodPressure >= 120 && maxBloodPressure < 130) || (minBloodPressure >= 80 && minBloodPressure < 85)) {
      bloodpressureVal = antihypertensiveFlg === 0 ? 3 : 10;
    } else {
      bloodpressureVal = antihypertensiveFlg === 0 ? 0 : 10;
    }
    return bloodpressureVal;
  }  

  /**
   * リスク因子（性別、年齢、喫煙、bmi、糖尿病、血圧）を加えた脳卒中リスク算出
   * @param {number} genderVal 性別算出値
   * @param {number} ageVal 年齢算出値
   * @param {number} smokingHabitVal 喫煙算出値
   * @param {number} bmiVal bmi算出値
   * @param {number} diabetesVal 糖尿病算出値
   * @param {number} bloodpressureVal 血圧算出値
   * @return {number} 脳卒中リスク算出値
   */
  static _getProbability(genderVal, ageVal, smokingHabitVal, bmiVal, diabetesVal, bloodpressureVal) {
    const tp = genderVal + ageVal + smokingHabitVal + bmiVal + diabetesVal + bloodpressureVal;
    return ((1 - Math.pow(0.9714, Math.exp(0.098417*tp - 2.126415))) * 100);
  }

  /**
   * アドバイスを生成する
   * @param {Object.<number>} inputData 入力値(性別
   *                                          年齢
   *                                          身長（cm）
   *                                          体重（kg）
   *                                          喫煙習慣
   *                                          糖尿病の治療の有無
   *                                          血糖値（空腹時）【mg/dl】
   *                                          血糖値（随時）【mg/dl】
   *                                          降圧剤
   *                                          最高血圧(収縮期)
   *                                          最低血圧(拡張期)
   *                                          HDLコレステロール
   *                                          LDLコレステロール
   *                                          総コレステロール
   *                                          中性脂肪)
   * @returns アドバイス
   * 
   */
  static takeAdvices({
                      gender,
                      age,
                      bodyHeight,
                      bodyWeight,
                      smokingHabit,
                      diabetesCureFlg,
                      bloodSugarLevelFasting,
                      bloodSugarLevelAnytime,
                      antihypertensiveFlg,
                      maxBloodPressure,
                      minBloodPressure,
                      hdlCholesterol,
                      ldlCholesterol,
                      totalCholesterol,
                      triglyceride}) {

    // 69歳を超えた場合、69歳とみなす
    age = CommonUtils.convertAge(age); 
  
    // アドバイス中間パラメタを取得する
    const { 
      genderValue, 
      smokingValue, 
      bmi,
      isHypertension,
      bloodSugarGrades,
      SugartoleranceGrades,
      maxBloodPressureGrades,
      minBloodPressureGrades,
      isHypoglycemia,
      isGoodHDL,
      isGoodTG,
      isGoodNonHdl,
      isCalculateRiskByBloodSugar,
      isCalculateRiskByBloodPressure,
      isCalculateRiskByBMI,
      riskBaseParameter,
    } = AdvicesUtils._calcAdvicesMiddleParameter(bodyHeight,
                                                 bodyWeight,
                                                 gender,
                                                 age,
                                                 smokingHabit,
                                                 antihypertensiveFlg,
                                                 maxBloodPressure,
                                                 minBloodPressure,
                                                 bloodSugarLevelFasting,
                                                 bloodSugarLevelAnytime,
                                                 hdlCholesterol,
                                                 ldlCholesterol,
                                                 totalCholesterol,
                                                 triglyceride,
                                                 diabetesCureFlg);

    // BMIアドバイス
    const {bmiId, bmiAdvices} = AdvicesLogic._getBMIAdvices(bmi);
    // 血糖値アドバイス
    const {bloodSugarId, bloodSugarAdvices} = AdvicesLogic._getBloodSugarAdvices(diabetesCureFlg, bloodSugarGrades);
    // 血圧アドバイス
    const {bloodPressureId, bloodPressureAdvices} = AdvicesLogic._getBloodPressureAdvices(antihypertensiveFlg, maxBloodPressureGrades, minBloodPressureGrades);
    // 血中脂質アドバイス
    const {bloodLipidsId, bloodLipidsAdvices} = AdvicesLogic._getBloodLipidsAdvices(genderValue, smokingValue, isHypertension, isHypoglycemia, isGoodHDL, isGoodTG, isGoodNonHdl);
    // タバコアドバイス
    const {smokingId, smokingAdvices} = AdvicesLogic._getSmokingAdvices(smokingValue);

    let isAllGood = 0;

    // 血糖、血圧、たばこ、脂質、BMIのすべてが問題なしの場合
    if (bmiId === 'BMI_LESS_THAN_25' &&
        bloodSugarId === 'ND' &&
        bloodPressureId === 'NH' &&
        bloodLipidsId === 'GOOD' &&
        smokingId === 'NS') {

      isAllGood = 1;
    }

    // すすめの生活習慣のID
    const key = AdvicesLogic._getRecommendationId(isGoodHDL, isGoodTG, isGoodNonHdl, triglyceride, bmi, smokingValue, isHypertension, diabetesCureFlg, SugartoleranceGrades);
    // すすめの生活習慣の内容を取得する
    const recommendation = AdvicesLogic._getRecommendationContent(key);

    // 性別算出値
    const genderVal = this._getGenderValue(gender);
    // 年齢算出値
    const ageVal = this._getAgeValue(age);
    // 喫煙算出値
    const smokingVal = this._getSmokingValue(smokingHabit, gender)
    // bmi算出値
    const bmiVal = this._getBmiValue(bmi);
    // 糖尿病算出値
    const diabetesVal = this._getDiabetesValue(diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime);
    // 血圧算出値
    const bloodpressureVal = this._getBloodpressureValue(antihypertensiveFlg, maxBloodPressure, minBloodPressure);
    // あなたのリスク
    const you = this._getProbability(genderVal, ageVal, smokingVal, bmiVal, diabetesVal, bloodpressureVal);
    // 十分に低いリスクの基準リスクを計算する
    const riskBase = this.calcBaseRisk(riskBaseParameter);

    if (you <= riskBase) {
      return {
        // すべてが問題なし
        allGood : {
          isAllGood : isAllGood,
        },

        // アドバイス
        Advices : {
          // BMIアドバイス
          bmiAdvices : bmiAdvices,
          // 血糖値アドバイス
          bloodSugarAdvices : bloodSugarAdvices,
          // 血圧アドバイス
          bloodPressureAdvices : bloodPressureAdvices,
          // 血中脂質アドバイス
          bloodLipidsAdvices : bloodLipidsAdvices,
          // タバコアドバイス
          smokingAdvices : smokingAdvices,
        },

        // すすめの生活習慣の内容
        habit : {
          recommendation : recommendation,
        },

        // リスク改善
        improveRisk : {
          // 現在のリスク
          you,
          // 改善血糖値
          improveBloodSugarRisk : undefined,
          // 改善血圧のコントロール
          improveBloodPressureRisk : undefined,
          // 禁煙する
          improveSmokingRisk : undefined,
          // 改善BMI
          improveBMIRisk : undefined,
          // すべて改善
          improveAll : undefined,
          // 改善必要ではない
          improveCount : 0,
        },
      };
    }

    // 改善項目数
    let improveCount = 0;

    // 血糖値良好リスク
    let goodBloodSugarRisk;
    // 糖尿病算出値
    let goodBloodSugarVal;

    // 血糖値が良好になると、あなたのリスクが最大低下
    if (isCalculateRiskByBloodSugar === CALCULATE_RISK_LOW_FLG.YES) {
      
      // 空腹時
      goodBloodSugarVal = this._getDiabetesValue(diabetesCureFlg, BLOOD_SUGAR_LEVEL_FASTING.LOW.value, undefined);

      goodBloodSugarRisk = this._getProbability(genderVal, ageVal, smokingVal, bmiVal, goodBloodSugarVal, bloodpressureVal);

      // 改善前と改善後一致ではない場合
      if (you !== goodBloodSugarRisk) {
        improveCount++;
      }
    }


    // 血圧良好算出値
    let goodBloodpressureVal;
    // 血圧値良好リスク
    let goodBloodPressureRisk;
    // 血圧のコントロールが良好になると、あなたのリスクが最大低下
    if (isCalculateRiskByBloodPressure === CALCULATE_RISK_LOW_FLG.YES) {

      goodBloodpressureVal = this._getBloodpressureValue(antihypertensiveFlg, maxBloodPressure >= 140 ? 100 : maxBloodPressure, minBloodPressure >= 90 ? 70 : minBloodPressure);

      goodBloodPressureRisk = this._getProbability(genderVal, ageVal, smokingVal, bmiVal, diabetesVal, goodBloodpressureVal);

      // 改善前と改善後一致ではない場合
      if (you !== goodBloodPressureRisk) {
        improveCount++;
      }
    }

    // 喫煙算出値
    let noSmokingVal;
    // 禁煙リスク
    let goodSmokingRisk;
    // 禁煙すると、あなたのリスクが最大低下
    if (smokingValue === SMOKING_HABIT.IS_SMOKING.value) {

      noSmokingVal = this._getSmokingValue(SMOKING_HABIT.NO_SMOKING.value, gender);

      goodSmokingRisk = this._getProbability(genderVal, ageVal, noSmokingVal, bmiVal, diabetesVal, bloodpressureVal);

      // 改善前と改善後一致ではない場合
      if (you !== goodSmokingRisk) {
        improveCount++;
      }
    }

    // BMI算出値
    let goodBmiVal;
    let goodBmiRisk;
    // BMIが25未満になると、あなたのリスクが最大低下
    if (isCalculateRiskByBMI === CALCULATE_RISK_LOW_FLG.YES) {

      goodBmiVal = this._getBmiValue(20);

      goodBmiRisk = this._getProbability(genderVal, ageVal, smokingVal, goodBmiVal, diabetesVal, bloodpressureVal);

      // 改善前と改善後一致ではない場合
      if (you !== goodBmiRisk) {
        improveCount++;
      }
    }


    // すべて良好
    let goodRisk;
    // 改善項目数が一つ以上の場合
    if (improveCount > 1) {
      goodRisk = this._getProbability(genderVal,
                                      ageVal,
                                      smokingValue === SMOKING_HABIT.IS_SMOKING.value ? noSmokingVal : smokingVal,
                                      isCalculateRiskByBMI === CALCULATE_RISK_LOW_FLG.YES ? goodBmiVal : bmiVal,
                                      isCalculateRiskByBloodSugar === CALCULATE_RISK_LOW_FLG.YES ? goodBloodSugarVal : diabetesVal,
                                      isCalculateRiskByBloodPressure === CALCULATE_RISK_LOW_FLG.YES ? goodBloodpressureVal : bloodpressureVal);
    }

    const results = {
      // すべてが問題なし
      allGood : {
        isAllGood : isAllGood,
      },

      // アドバイス
      Advices : {
        // BMIアドバイス
        bmiAdvices : bmiAdvices,
        // 血糖値アドバイス
        bloodSugarAdvices : bloodSugarAdvices,
        // 血圧アドバイス
        bloodPressureAdvices : bloodPressureAdvices,
        // 血中脂質アドバイス
        bloodLipidsAdvices : bloodLipidsAdvices,
        // タバコアドバイス
        smokingAdvices : smokingAdvices,
      },

      // すすめの生活習慣の内容
      habit : {
        recommendation : recommendation,
      },

      // リスク改善
      improveRisk : {
        // 現在のリスク
        you,
        // 改善血糖値
        improveBloodSugarRisk : (isCalculateRiskByBloodSugar === CALCULATE_RISK_LOW_FLG.YES && goodBloodSugarRisk !== you) ? goodBloodSugarRisk : undefined,
        // 改善血圧のコントロール
        improveBloodPressureRisk : (isCalculateRiskByBloodPressure === CALCULATE_RISK_LOW_FLG.YES && goodBloodPressureRisk !== you) ? goodBloodPressureRisk : undefined,
        // 禁煙する
        improveSmokingRisk : (smokingValue === SMOKING_HABIT.IS_SMOKING.value && goodSmokingRisk !== you) ? goodSmokingRisk : undefined,
        // 改善BMI
        improveBMIRisk : (isCalculateRiskByBMI === CALCULATE_RISK_LOW_FLG.YES && goodBmiRisk !== you) ? goodBmiRisk : undefined,
        // すべて改善
        improveAll : (improveCount > 1 && goodRisk !== you) ? goodRisk : undefined,
        // 改善必要ではない
        improveCount : improveCount,
      },
    }

    return results;
  }


  /**
   * リスク計算(十分に低い)
   * @param {number} gender 性別
   * @param {number} age 年齢
   * @param {number} smokingHabit 喫煙習慣
   * @param {number} bmi BMI
   * @param {number} diabetesCureFlg 糖尿病の治療
   * @param {number} bloodSugarLevelFasting 血糖値（空腹時）
   * @param {number} bloodSugarLevelAnytime 血糖値（随時）
   * @param {number} antihypertensiveFlg 降圧剤
   * @param {number} maxBloodPressure 最高（収縮期）血圧
   * @param {number} minBloodPressure 最低（拡張期）血圧
   * @return {Object.<Object>} 
   */

  static calcBaseRisk({ gender, age, smokingHabit, bmi, diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime, antihypertensiveFlg, maxBloodPressure, minBloodPressure }) {
    // 69歳を超えた場合、69歳とみなす
    age = CommonUtils.convertAge(age); 

    const genderVal = this._getGenderValue(gender);
    const ageVal = this._getAgeValue(age);
    const bmiVal = this._getBmiValue(bmi);
    const diabetesVal = this._getDiabetesValue(diabetesCureFlg, bloodSugarLevelFasting, bloodSugarLevelAnytime);
    const bloodpressureVal = this._getBloodpressureValue(antihypertensiveFlg, maxBloodPressure, minBloodPressure);

    return this._getProbability(genderVal, ageVal, this._getSmokingValue(smokingHabit, gender), bmiVal, diabetesVal, bloodpressureVal);

  }
}

export default CerebralStrokeLogic
